package myredis

import (
	"context"
	"time"

	L "gitee.com/lsof/mylog"

	"github.com/go-redis/redis/v8"
)

type MyRedis struct {
	redis *redis.Client
	ctx   context.Context
}

func NewMyRedis(addr string, pass string, db int) *MyRedis {
	L.Debugf("new redis connection: %s, %s, %d", addr, pass, db)
	return &MyRedis{
		redis: redis.NewClient(&redis.Options{
			Addr:     addr,
			Password: pass, // no password set
			DB:       db,   // use default DB
		}),
		ctx: context.Background(),
	}
}

func (r *MyRedis) Pub(channel string, msg string) error {
	L.Debugf("redis: Pub %s %v", channel, msg)
	_, err := r.redis.Publish(r.ctx, channel, msg).Result()
	if err != nil {
		L.Errorf("redis: Publish %s %s error:%v", channel, msg, err)
	}
	return err
}

func (r *MyRedis) Get(key string) (string, error) {
	L.Debugf("redis: Get %s", key)
	value, err := r.redis.Get(r.ctx, key).Result()
	if err != nil {
		if err == redis.Nil {
			L.Warnf("redis: Get %s error:%v", key, err)
		} else {
			L.Errorf("redis: Get %s error:%v", key, err)
		}
	}
	return value, err
}

func (r *MyRedis) Set(key string, val interface{}) (string, error) {
	L.Debugf("redis: Set %s %v", key, val)
	ret, err := r.redis.Set(r.ctx, key, val, 0).Result()
	if err != nil {
		L.Errorf("redis: Set %s %v error:%v", key, val, err)
	}
	return ret, err
}

func (r *MyRedis) HGet(key string, field string) (string, error) {
	L.Debugf("redis: HGet %s %s", key, field)
	ret, err := r.redis.HGet(r.ctx, key, field).Result()
	if err != nil {
		if err == redis.Nil {
			L.Warnf("redis: HGet %s %s error:%v", key, field, err)
		} else {
			L.Errorf("redis: HGet %s %s error:%v", key, field, err)
		}
	}
	return ret, err
}

func (r *MyRedis) HSet(key string, vals map[string]interface{}) (int64, error) {
	L.Debugf("redis: HSet %s %v", key, vals)
	ret, err := r.redis.HSet(r.ctx, key, vals).Result()
	if err != nil {
		L.Errorf("redis: HSet %s %v error:%v", key, vals, err)
	}
	return ret, err
}

func (r *MyRedis) Expire(key string, expire time.Duration) error {
	L.Debugf("redis: Expire %s %s", key, expire)
	_, err := r.redis.Expire(r.ctx, key, expire).Result()
	if err != nil {
		L.Errorf("redis: Expire %s %s error:%v", key, expire, err)
	}
	return err
}

func (r *MyRedis) Exists(key string) bool {
	L.Debugf("redis: Exists %s", key)
	val, err := r.redis.Exists(r.ctx, key).Result()
	if err != nil {
		L.Errorf("redis: Exists %s error %v", key, err)
		val = 0
	}
	if val != 0 {
		return true
	} else {
		return false
	}
}

func (r *MyRedis) Keys(pattern string) ([]string, error) {
	L.Debugf("redis: Keys %v", pattern)
	rs, err := r.redis.Keys(r.ctx, pattern).Result()
	if err != nil {
		L.Errorf("redis: Keys %v err:%v", pattern, err)
	}
	return rs, err
}

func (r *MyRedis) Del(keys ...string) error {
	L.Debugf("redis: Del %v", keys)
	_, err := r.redis.Del(r.ctx, keys...).Result()
	if err != nil {
		L.Errorf("redis: Del %v err:%v", keys, err)
	}
	return err
}

func (r *MyRedis) Dels(pattern string) error {
	ks, err := r.Keys(pattern)
	if err != nil {
		return err
	}
	if len(ks) > 0 {
		return r.Del(ks...)
	}
	return nil
}
